Sound XObject Instructions

version 2.1

What is it?
The Sound XObject, designed for the Macintosh and Windows, can enable a Director-generated application to record and play sounds directly to and from disk. It records/plays AIFF and AIFF-C files on the Macintosh and .WAV files under Windows.

Recording features include support for 8 or 16-bit recording, 11kHz through 44kHz sampling rates and recording compressed sounds (all of these are available if the input device supports it). A recording may be stopped, paused and resumed at any point; also, the microphone levels can be queried anytime. All recording is done directly to disk and is done asynchronously, meaning that animation, Lingo scripts and anything else in Director can run while a sound is being recorded.

Like with sound recording, playing back a sound is always done asynchronously and from disk. Sounds can be paused/resumed in the middle of playback and a segment of a sound can be played as well.

Each instance of the Sound XObject uses just one sound channel and does not conflict with Director’s sound channels. Due to limitations of Windows, only one sound may be recorded or played at a time but on the Macintosh, multiple instances of the XObject can be created to control multiple sound channels.

What’s New?
The Sound XObject 2.1 is far more powerful than earlier versions of the Sound XObject and includes the following enhancements:

Version 2.0 added the following features to 1.0 and 1.1 versions
- Asynchronous recording and playback of sounds
- Support for AIFF and AIFF-C sounds (Macintosh) and .WAV sounds (Windows)
- The ability to pause, resume and stop recording and playback of sounds
- Recording and playback to and from disk
- The ability to query the current microphone input levels
- Can check to see if the microphone is plugged in
- Can check the available recording space on disk (Macintosh only)

The Sound XObject 2.1 has several improvements
- Better error-reporting with the Windows XObject
- Full Windows 95 compatibility
- The ability to get information about a sound that is to be played back or has just been recorded:
	- the number of channels
	- the number of bytes of sound data
	- the sample rate of a sound
	- the sample depth
	- the length (in milliseconds)
	- the throughput (bytes/second) of the sound data
- You can now activate a minor feature called "QuickLevels" which can turn off error-checking when querying the levels meter to get faster readings. Obviously, this feature should be used cautiously.

Licensing the Sound XObject

This is a demo version of the Sound XObject which is fully functional except that each time you play or record a sound, a dialog box indicating that this is an unregistered copy will get displayed.

To prevent the dialog box from being displayed, you will need to license the XObject from Red Eye Software. The licensing fees are:

- $200/title for either the Macintosh or the Windows version of the XObject 
- $300/title for both the Macintosh and the Windows version of the XObject.

All you need to do is fax or send me one of the licensing agreements located in the "LICENSES" directory. I will then immediately e-mail you serial numbers which can be used with the mRegister method to "unlock" the XObject. Payment should then be made from 30 days after receiving the serial numbers from me.

When filling out the licensing agreements, please be sure to include ALL of the information about you company especially the name of the product you will be using the XObject with, your e-mail address and your fax number.

You can reach me by the following means:

E-mail:
kildall@eskimo.com
kildall@aol.com
72703.451@compuserve.com

website: http://www.eskimo.com/~kildall

Regular mail:
Red Eye Software
1516 Second Ave., Suite 300
Seattle, WA 98101

Fax:
fax: 206-624-9866

Using the XObject:

The Sound XObject 2.0 includes the following methods: mNew, mDispose, mRegister, mGetError, mGetInfo, mStatus, mCheckInputDevice, mSetSoundFile, mClearSoundFile, mPlay, mRecord, mStop, mPause, mResume, mGetCurrentTime, mIsASound, mDeleteSound, mSetStartTime, mSetEndTime, mClearStartEnd, mSetSampleRate, mSetSampleDepth, mSetCompression, mGetInputLevel and mFreeRecordingTime. These will all be explained below.

mNew

Returns: An instance of the XObject or <void> if failure.
Parameters: A number indicating the size of the playback buffer, pass zero to use the default buffer. 

The mNew method creates an instance of the XObject in RAM and does not take any arguments. After calling this function, the Sound XObject will take control of a sound channel and will relinquish the sound channel only after the mDispose method gets called.

It will also attempt to open the current sound input driver and will close it when mDispose gets called. The Sound XObject will still be able to use all of its playback functions if the sound recording driver cannot be used.

Macintoshes have different numbers of sound channels depending upon the CPU. Director always occupies two sound channels and each instance of the Sound XObject will consume another available sound channel. If no more sound channels are available, the mNew method will fail and an instance of the XObject will not be created.

After initializing the XObject, you should test to make sure that it was initialized properly with the objectP command, check to see if any errors occurred and check to see if the sound input driver is plugged in and if the microphone is connected:

Important: The default buffer size is 40960 bytes for the Macintosh and 88200 bytes for Windows. If you pass in any value less than this, the buffer will automatically be set to the default size. As I described in the “Advanced Tips & Techniques” section of this document, passing in a larger buffer size may result in a smoother playback at the expense of memory.

Example scripts:

-- This uses the default size for the playback buffer which is
-- 40960 bytes (Mac) or 88200 bytes (Windows). To use the default buffer
-- size, just pass in a value of zero as the parameter to mNew

-- The XObject file is called “Sound XObj” on the Macintosh side and
-- “XSound.DLL” for Windows
on InitializeSound
	-- Its best to have the instance of the Sound XObject be a
	-- global variable
	global gSoundObj
	
	if the machineType = 256 then openxlib “XSOUND.DLL”
	else openxlib “Sound XObj”

	-- Dispose of any old instances of the XObject
	if objectP(gSoundObj) then gSoundObj(mDispose)

	-- “XSound” is the name of the XObject library file
	set gSoundObj = XSound(mNew, 0)

	if objectP(gSoundObj) then
		--XObject initialized properly, check for errors and microphone
		if gSoundObj(mGetError) <> 0 then alert “an error occurred initializing the XObject”
	
		-- Note: see error tables for details on what all the error
		-- numbers mean
		set mikeStatus = gSoundObj(mCheckInputDevice)
		if mikeStatus = -2 then alert “Unable to open the sound input driver”
		else if mikeStatus = -5 then alert “Microphone is not plugged in”

     go to “Rest of movie”
	
	else
		--XObject failed to initialize
		alert “Sound XObject failed to initialize.”
	end if
end InitializeSound

mDispose

Returns: Nothing
Parameters: None

The mDispose method clears the instance of the XObject from RAM, releases the sound channel from memory and closes the sound input driver or the MCI device if it was opened. You must always call this method when you are finished with that instance of the XObject. A useful technique is to place a call to mDispose in the stopMovie handler (in your Movie Script). This way, when building and running a kiosk/presentation, you will not generate unusual scripting errors or negatively impact memory.

If a sound is being played or recorded, mDispose will stop the playback or recording. The recorded file will be left on the disk.

Example scripts:

on stopMovie
	global gSoundObj 
	--where gSoundObj is the instance of Sound XObject

	if objectP(gSoundObj) then gSoundObj (mDispose)
end stopMovie

Warning: If you do not dispose of the XObject, the sound channel will never be released and the sound input driver will not be able to be reopened.

Serious Warning: If you quit Director while a sound is being played or recorded (or if the sound is paused) without calling mDispose, you will likely crash the computer.

Note: If you get a scripting error or run into another circumstance such that the mDispose method doesn’t get executed, you can still dispose of the XObject, by opening up the Message Window, typing in showGlobals (the instance of the Sound XObject should always be a global variable), seeing if the object is still in memory. If so, the message window output will look something like:

-- Global Variables --
gSoundObj = <Object:77cc88>

You can then type in:

gSoundObj(mDispose)

to release the instance of the XObject from memory.

One final note: When developing applications on the PC, always stop your movies with <Ctrl>-.  (Control key and period) rather than hitting the escape key.

mRegister

Returns: Nothing
Parameters: A string indicating the serial number

The mRegister method is for companies which have licensed the XObject and removes the "unregistered" dialog box. This method should be called immediately after mNew.

Example scripts:

on initializeXObject
	global gSoundObj 
	--where gSoundObj will be an instance of Sound XObject
	
	-- dispose of any previous instances
	if objectP(gSoundObj) then gSoundObj (mDispose)

	set gSoundObj = XSound(mNew, 0)

	if( gSoundObj ) then

		-- Register the Windows version
		if the machineType = 256 then gSoundObj(mRegister, "??? Windows" )

		-- Register the Macintosh version
		else gSoundObj(mRegister, "??? Macintosh" )
	
	end if

end initializeXObject

• Substitute your serial number for the one with the question marks.

mGetError

Returns: The last error number generated by one of the XObject methods, zero if none
Parameters: None

Since nearly all of the Sound XObject methods return an error code, mGetError only needs to be used in the following circumstances:

- Immediately after creating an instance of the XObject with mNew
- After spooling a sound to be played or recorded, to be safe (but not usually necessary), call mGetError once in a while to make sure that recording or playing is taking place normally.

Here is a useful table of all of the error numbers the Sound XObject is likely to generate, with many of the error numbers applying to both platforms:

Table 1	Sound XObject Error Numbers
	
Error Number	Meaning	Platform	
0	No error	Macintosh and Windows	
			
-1	You passed in a bad parameter	Macintosh and Windows	
-2	Unable to open sound input driver	Macintosh and Windows	
-3	No sound has been specified	Macintosh and Windows	
-4	Sound is busy (recording, playing or paused)	Macintosh and Windows	
-5	Input device not connected	Macintosh and Windows	
-6	Unable to tell if input device is connected	Macintosh and Windows	
-7	Too much hard drive space	Macintosh only	
-8	MCI device not open	Windows only	
-9	Invalid sound file	Macintosh and Windows	
-10	Sound not loaded for playback	Macintosh and Windows	
-33	Directory full	Macintosh only	
-35	Bad pathname	Macintosh only	
-36	File I/O error	Macintosh only	
-37	Bad filename	Macintosh only	
-42	Too many files open	Macintosh only	
-43	File not found	Macintosh and Windows	
-44	Disk is write-protected	Macintosh only	
-45	File is locked	Macintosh only	
-46	 Volume is locked	Macintosh and Windows	
-47	File is busy	Macintosh only	
-48	File already exists	Macintosh and Windows	
-49	File already opened	Macintosh only	
-50	Invalid selection range	Macintosh only	
-108	Out of memory	Macintosh only	
-120	Bad pathname	Macintosh only	
-201	Insufficient sound hardware	Macintosh only	
-203	Corrupt sound channel	Macintosh only	
-206	Bad file format	Macintosh only	
-207	Out of memory	Macintosh only	
-208	Corrupt or bad file	Macintosh only	
-209	Sound channel is busy	Macintosh only	
-210	Sound buffer is too small	Macintosh only	
-220	Sound input driver unavailable	Macintosh only	
-221	Error accessing the sound input device	Macintosh only	
-223	Compression type invalid or unavailable	Macintosh and Windows	
-224	Hard drive too slow to record	Macintosh only	
-225	Sample rate invalid or unavailable	Macintosh and Windows	
-226	Sample depth invalid or unavailable	Macintosh and Windows	
-227	Sound input device is busy	Macintosh only	
-228	Unable to open sound driver	Macintosh only	
			
262	MCI hardware error	Windows only	
264	Out of memory (MCI)	Windows only	
266	Unable to load MCI driver	Windows only	
275	File not found or not a WAVE file	Windows only	
276	Device not ready	Windows only	
286	Disk is write-protected	Windows only	
296	Invalid file	Windows only	
304	Bad pathname	Windows only	
326	Invalid WAVE output driver settings (playing)	Windows only	
328	Invalid WAVE output driver settings (recording)	Windows only	
349	Disk full	Windows only	

Look at the mNew example script to see a good example of when to use mGetError.

mGetInfo

Returns: A string or a number indicating the information requested. A negative number will always signify an error. If a negative number is returned by this function, consult the error table listed in mGetError for an explanation of what went wrong.

Parameters: A number indicating the information that you want to retrieve, listed below.

Passed Parameter	Information Requested		Returns
	1			Buffer size of the			an integer describing the number of bytes
				sound channel			that the sound channel uses for internal 									buffering

	2			Whether the CPU supports		true or false
				recording while playing a sound

	3			The name of the currently		a string containing the name
				selected input device
	
	4			Not used				n/a

	5			Version of the Sound Manager	a string, e.g. “3.0”

	6			The maximum sample depth at	an integer, e.g. 8
				which the input device can
				record, either 8-bit or 16-bit

	7			The maximum sample rate of		an integer representing the sample rate
				which the input device is		(see table 2 below)
				capable
	
	8			The current sample depth of the	an integer, e.g. 8
				sound input device

	9			The current sampling rate of the	an integer representing the sample rate
				input device				(see table 2)

	10			The current compression type of	an integer representing the compression type
				the input device			(see table 3)

	11			Number of allocated channels	the total number of channels that are busy on 									this machine, including the one used by this
									instance of the XObject. Director always 									reserves 2 sound channels.

	12			Number of bytes of data in a		an integer representing the byte count
				sound loaded for playback

	13			Number of bytes of data in a		an integer representing the number of 
				sound loaded for playback		channels

	14			The sample depth of a playback	an integer representing the sample
				sound					depth (e.g. 8 or 16)
	
	15			The sample rate of a playback	an integer representing the sample
				sound					depth. This follows a different notation
									than mSetSampleRate such that a
									22.050 kHz sound will return a
									value of 22050.

	16			Number of sample frames of a	an integer representing the sample
				playback sound			frames

	17			Whether "Quick Levels" are		0 means that they are off and 1 means
				on or off				they are on.	

	18			The length of a playback sound,	an integer representing the length of a
				in milliseconds			playback sound

	19			The compression ratio of a sound	an integer representing the compression
									ratio of a sound, i.e. 3 = MACE 3 to 1,
									4 = IMA 4:1.

	20			Whether playthrough is on or off	0 means that it is off, 1 means it is on
				(always off for Windows)

Notes on mGetInfo:
• Calling (mGetInfo,2) [recording while playing] will always return false under Windows since Windows is unable to record and play sounds at the same time.
• Calling (mGetInfo,3) [the input device name] under Windows will return the name of the sound card used for recording. Sometimes, this call will not work properly and will return an empty string. I noticed that with my SoundBlaster 16-bit card. If no sound has been specified with mSetSoundFile(), this will return “PC Sound Card”.
• Calling (mGetInfo,4) [the Sound Manager version] under Windows will return an empty string since the Sound Manager is a component of the Mac OS.
• Calling (mGetInfo,10) [current compression type] under Windows will always return a value of 1 since MACE compression does not apply to WAVE files.
• Calling (mGetInfo,11) [number of allocated channels] under Windows will always return a value of 1.
• Calling(mGetInfo,20) [playthrough] under Windows will always return a value of 1.

Table 2	Sample rates and their numerical equivalents
	
Integer Representation	Sample Rate	
1	11.127 kHz ( “11 kHz” )	
2	11.025 kHz	
3	22.255 kHz ( “22 kHz” )	
4	22.050 kHz	
5	44.100 kHz	
6	Best available sample rate	
7	Unknown sample rate	

Table 3	Compression types and their numerical equivalents
	
Integer Representation	Compression Type	
1 or 0	No compression	
2	µLaw (2:1)	
3	MACE 3:1	
4	IMA 4:1	
6	MACE 6:1	

Information types: 3, 6, 7, 8, 9 and 10 all require that the sound input driver is open. You may want to use the method mCheckInputDriver before calling mGetInfo for this information.

Information types: 12-17 amd 19-20 all require that a sound is loaded for playback. This will return a -10 error otherwise.

Since mGetInfo can return either a string or a number depending upon the information being requested, use the two Lingo functions: integerP() and stringP() to check the return values of this function when they can be ambiguous.

Example scripts:

-- Puts the name of the input device name in a field
on GetInputDeviceName
	global gSoundObj

	if objectP(gSoundObj) then
		
		set driverStatus = gSoundObj(mCheckInputDriver)

		if driverStatus = -2
		-- The input driver cannot be opened (either another application
		-- has it open or it is not loaded as an extension)
			put “N/A” into field “microphone”
		else
			set result = gSoundObj(mGetInfo,3)

			-- If a string was returned, then no error occurred
			if stringP(result) then put result into field “microphone”
			else put “error” into field “microphone”		
		
		end if
	end if
end GetInputDeviceName

-- Returns true if the input device can record 16-bit sounds
on CanRecord16bit
	global gSoundObj

	if objectP(gSoundObj) then
		
		if gSoundObj(mGetInfo,6) < 16 then return false
		else return true
	
	end if
end CanRecord16bit

-- Returns true if we can record a sound while playing a sound at
-- the same time (remember, the same instance of the Sound XObject
-- can’t do this)
on CanDoKerioke
	global gSoundObj

	if objectP(gSoundObj) then
		return gSoundObj(mGetInfo,2)
	end if

end CanDoKerioke

mSetInfo

Returns: An error number or zero if no error occurred.

Parameters:

<information to set> A number indicating the type information you want to set

<value to set it to> The value of the information you want to set

mSetInfo is the complement of mGetInfo and only has a few things you can set.

Passed Parameter	Information to set		Possible values
	17			"Quick Levels"		0 = turn quick levels on
								1 = turn quick levels off

	20			Playthrough			0 = turn playthrough on
								1 = turn playthrough off

Notes:

• "Quick Levels" affects the retrieval rate of the input levels with mGetInputLevel. By turning it on, no error-checking will be performed. The default state is off.

Examples:

gSoundObj(mSetInfo, 17, 1)    -- This turns Quick Levels on

To turn Quick Levels back off, use the script:

gSoundObj(mSetInfo, 17, 0)

Warning: If you turn error-checking off, you may get bizarre readings from the input meter. Proceed at your own confusion.
		
• Playthrough can only be set on certain Macintosh models and indicates whether or not the recording will be echoed in the speakers.

mStatus

Returns: A number indicating the status of the sound
Parameters: None

The mStatus method returns a number indicating the status of the sound in the sound channel. The return values are:

Number		Meaning
0				No sound specified for recording/playback

1				A sound file is open and ready to be played

2				A sound file has been created and is ready to be recorded

3				A sound has been created and can be recorded or played

4				A sound is being played

5				A sound is being recorded

6				A sound is paused in the middle of playback

7				A sound is paused in the middle of a recording

8				An error occurred while recording

9				MCI driver is not ready (Windows only)

10				MCI driver is busy. Please wait (Windows only)
	
This function performs similar functionality as the Lingo function, soundBusy, except that it provides more detailed information.

Example scripts:

-- Returns true if the sound is recording, playing or paused
on IsTheSoundBusy
	global gSoundObj

	if objectP(gSoundObj) then
		
		set status = gSoundObj(mStatus)

		if status = 4 or status = 5 or status = 6 or status = 7 then¬
return true

		else return false

	end if
end IsTheSoundBusy

-- Returns true if a sound is ready to be recorded
on ReadyToRecord
	global gSoundObj

	if objectP(gSoundObj) then

		set status = gSoundObj(mStatus)

		if status = 2 or status = 3 then return true
		else return false

	end if

end ReadyToRecord

Note: A status number of 8 indicates that an error was registered after calling mRecord. The mRecord section explains how to best handle this condition.

mCheckInputDevice

Returns: An error code indicating the status of the input device (this is whatever is selected in the “Sound” control panel.
Parameters: 1 optional parameter, either “connect” or “disconnect” indicating whether we are to try to reestablish a connection with the sound input driver or disconnect from the sound input driver that is currently open. Usually, you won’t need to use this.

mCheckInputDevice is a handy way to check the computer to see if its ready to record sounds before having to wait for the user to press a record button.

Expected return values are:

Return Value		Meaning
	0			Device is connected
	-2			Sound input driver not open
	-5			Microphone not plugged in (the sound driver is open)
	-6			Unable to tell if the microphone is plugged in (the sound driver is open)
	-108		Out of memory (very rare since this function uses a tiny bit of extra memory)
	-228		Unable to open sound driver

Return values of 0, -2, -5 and -6 indicate that no error has occurred with this function. If you get a -6 return, it means that the Sound Manager can’t tell if the input device is connected or not.

Note: It is impossible for the Windows XObject to determine whether or not a microphone is plugged in and so this method will usually return a value of -6. For the Macintosh, only newer machines can find out whether or not the microphone is physically connected.

Example Scripts:

-- Check mike
on CheckMike
	global gSoundObj

	if objectP(gSoundObj) then

		set mikeStatus = gSoundObj(mCheckInputDevice)
		
		if mikeStatus = 0 then
			go to frame “time to record”
		else if mikeStatus = -2 then
			if AttemptToReconnect() = true then ¬
go to frame “time to record”
		else if mikeStatus = -5
			alert “Please plug in your microphone before trying ¬
to record”
			go to frame “time to record”
		else if mikeStatus = -6
			alert “Please verify that your microphone is plugged ¬
before recording”
			go to frame “time to record”
		end if			
	end if
end CheckMike

-- Tries to reopen the sound driver, returns true if successful
on AttemptToReconnect
	global gSoundObj

	set result gSoundObj(mCheckInputDevice, “connect”)

	if result = 0 then
		return true
	else if result = -5 or result = -6
		alert “Make sure the microphone is plugged in”
		return true
	else
		return false
	
end AttemptToReconnect

mSetSoundFile

Returns: An error number, zero if no error occurred
Parameters:

<sound> The full pathname of an AIFF or WAVE file to be played, recorded or both

<recording or playing> Pass a ‘1’ if you want to have this sound played and pass a ‘2’ if you want it recorded. See mRecord for information on recording then playing back a sound.

<overwrite files> Pass this 3rd parameter only if you are recording a sound. This should be true if you want to overwrite any existing files or resources by the same and false if not.

mSetSoundFile will specify an AIFF or WAVE sound file to be played or recorded. The sound may be compressed (this applies to AIFF files). The method must be called before mPlay or mRecord gets called, otherwise these two methods will trigger an error.

mSetSoundFile is useful for optimization sound playback and recording. This will open a file, creating it first when recording a sound and load all of the necessary information so that when mPlay or mRecord gets called, the playback and recording should occur immediately.

If any sounds are being recorded or played when this method is called, playback or recording will immediately stop, the old sound will be closed and the new sound loaded.

When recording, if the last parameter is set to true, after a recording is finished, the file may be played or recorded to again. Otherwise, it may just be played.

Common errors are:

Error Number				Meaning
	0					No error

	-1					Bad parameter

	-2					Sound input driver not open (recording sounds only)

	-33				Directory full (recording sounds only)
	
	-35				Bad pathname (recording sounds only)

	-36				File I/O error. May be a bad disk (recording sounds only)

	-42				Too many files open

	-43				The file does not exist (playing sounds only)

	-44				Disk is write-protected (recording sounds only)

	-45				File is locked

	-46				Volume is locked (e.g. a CD) (recording sounds only)

	-47				File is busy

	-48				A sound by this name already exists (recording sounds without 
						overwriting existing files)

	-49				The file is already opened (being written to)

	-120				Bad pathname (recording sounds only)

	-223				Invalid compression type (problem w/the sound driver)

Example scripts:

on PrepareForPlay
	global gSoundObj

	set result = gSoundObj(mSetSoundFile, the pathname & “Ghost Sound”, 1)

	if result <> 0 then
		alert “An error occurred with mSetSoundFile”
	else
		go to “Play Sound”
	end if

end PrepareForPlay

-- Create a file to record to, overwriting any pre-existing files
on PrepareForRecord
	global gSoundObj

	set result = gSoundObj(mSetSoundFile, the pathname & “Recorder”, 2, true)

	if result <> 0 then
		alert “An error occurred with mSetSoundFile”
	else
		go to “Record Sound”
	end if

end PrepareForRecord

mClearSoundFile

Returns: An error number, zero if none
Parameters: None

mClearSound will close any open files and unload any irrelevant sound information from memory, essentially “undoing” the effects of mSetSoundFile.

Note: This function will return an error if a sound is currently being played, recorded or paused.

Common errors are:

Error Number				Meaning
	0					No Error
	
	-4					A sound is currently being played, recorded or paused

	-36				File I/O error. May be a bad disk.

	-45				File is locked

	-47				File is busy

mPlay

Returns: Anerror number, zero if no error occurred
Parameters: None

mPlay will begin playback of a sound which has been specified with the mSetSoundFile method. When the sound is done playing, the XObject will automatically stop the sound.

Common errors are:

Error Number			Meaning
	0				No Error
	
	-3				A sound has not been loaded (see mSetSoundFile)

	-4				A sound is currently being played, recorded or paused
	
	-50			Invalid selection range (the start and end points set by mSetStartTime and
					mSetEndTime extend beyond the length of the sound)

	-201			Insufficient sound hardware

	-203			The sound channel is corrupt (shouldn’t happen)

	-206			Bad file format

	-207			Out of memory or not enough buffer space

	-208			Bad file format (not an AIFF file or the file is corrupted)

	-209			The sound channel is busy

	-210			The sound buffer is too small (shouldn’t happen)

	-223			Invalid compression type (problem w/the sound file and sound driver)

	275			Invalid file (may not be a WAVE file)

	326			Invalid WAVE output settings (common if the sound card is not configured 					correctly)

Example scripts:

on StartTheSound
	global gSoundObj

	set result gSoundObj(mPlay)

	if result <> 0 then
		-- an error occurred
		alert “Error playing the sound”
	end if

end StartTheSound

mRecord

Returns: an error number, zero if no error occurred
Parameters: none

mRecord will begin a recording into a file which has been specified with mSetSoundFile. The recording will continue for until mStop gets called or until an error occurs (such as running out of disk space). Once recording begins, the XObject returns control of CPU processing to Director.

After mRecord is called, you should make sure the recording is proceeding without any errors by checking mStatus as often as possible. A good way to do this is to call mStatus in your on idle handler. If mStatus returns an value of 8, then you had a recording error. The file will automatically be deleted and you can get the recording error by checking mGetError.

Note: There is a 2 gigabyte limit on the size of a file to be recorded. If this is a problem, you may want to think about a different career.

Yet another note: If the specified recording time is greater than the free time on the hard drive of the current file, the sound will record for as long as there is disk space to store the sound file (this is for the Macintosh only).

Potential errors are:

Error Number			Meaning
	0				No Error
	
	-1				Bad parameter

	-3				A sound has not been loaded (see mSetSoundFile)

	-4				Sound busy (currently being recorded, played or paused)

	-205			Corrupt sound channel

	-220			Sound input driver not available

	-221			Error accessing sound input device

	-224			Hard drive too slow to record
	
	-227			Sound input device is busy

	328			Invalid WAVE input settings (common if the sound card is not configured 					correctly)

-- Will initiate a recording
on StartRecording
	global gSoundObj

	if objectP(gSoundObj)

		-- Pass no parameter if we want to record as long as possible
		set err = gSoundObj(mRecord)
		if err <> 0 then alert “A recording error occurred”
		else set gRecording = true
	end if
end StartRecording

-- An idle handler which checks to see if we are recording
-- and if no errors have occurred
on idle
	global gSoundObj, gRecording

	if gRecording = true and objectP(gSoundObj) then
		if gSoundObj(mStatus) = 8 then
			-- a recording error occurred
			set err = gSoundObj(mGetError)

			if err = -34 then alert “Disk is full”
			else alert “An error occurred while recording”
			
			-- unload the file information
			gSoundObj(ClearSoundFile)
		end if
	end if
end idle

mStop

Returns: an error number, zero if no error occurred
Parameters: None

mStop will stop the playback of a sound which is current playing or the recording of a sound which is currently being recorded. If no sound is playing, mStop will do nothing and return zero.

Possible errors are:

Error Number			Meaning
	0				No Error

	-3				A sound has not been loaded (see mSetSoundFile)

	-205			Corrupt sound channel

	-221			Error accessing sound input device

	286			Unable to save file because disk is write-protected

	349			Unable to save file because disk is full

Example scripts:

on StopThisCrazySound
	global gSoundObj

	gSoundObj(mStop)

end StopThisCrazySound

mPause

Returns: an error number, zero if no error occurred
Parameters: None

mPause will pause a sound which is current playing or recording. If no sound is playing or recording, or if the sound is already paused, mPause will do nothing and return zero.

Possible errors are:

Error Number			Meaning
	0				No Error

	-3				A sound has not been loaded (see mSetSoundFile)

	-205			Corrupt sound channel

	-221			Error accessing sound input device

Example scripts:

on PauseTheSound
	global gSoundObj

	gSoundObj(mPause)

end PauseTheSound

mResume

Returns: an error number, zero if no error occurred
Parameters: None

mResume will resume the playback of a paused sound. If the sound is currently not being paused, mResume will do nothing and return zero.

Possible errors are:

Error Number			Meaning
	0				No Error

	-3				A sound has not been loaded (see mSetSoundFile)

	-205			Corrupt sound channel

	-221			Error accessing sound input device

Example scripts:

on ResumeTheSound
	global gSoundObj

	gSoundObj(mResume)

end ResumeTheSound

mGetCurrentTime

Returns: The current playback time of a sound, in milliseconds.
Parameters: None

mGetCurrentTime indicates where in the sound file the playback is taking place.

Example scripts:

on GetSoundTime
	global gSoundObj 
	
	set result = gSoundObj(mGetCurrentTime)

end GetSoundTime

Note: I did not test this function on very many configurations. For the Macintosh, this return value will not be very accurate on all machines. I noticed this on a PowerMac 6100/60 running the Sound Manager 3.1 especially with sounds that had lower sampling rates, sample depths and used compression.

mIsASound

Returns: True if the passed filename is a sound, false if the passed filename is not a sound file.
Parameters:

<Sound name> The full pathname of an AIFF or WAVE file.

mIsASound checks to see if the passed filename is actually a file. It does not do any verification of the file itself, nor does it check the file type.

Sample scripts:

-- Given the name of a sound (e.g. “Boom”), this checks to see
-- if it is in the same folder as the application
on IsASound localName
	global gSoundObj

	return gSoundObj(mIsASound, the pathname & localName )
end IsASound

-- Looks for a specific sound
on IsMySound
	global gSoundObj

	gSoundObj(mIsASound, “HD:Sounds:Nails on Chalkboard” )
end IsMySound

mDeleteSound

Returns: an error number,, zero if none
Parameters:

<Sound name> The full pathname of an AIFF or WAVE file.

mDeleteSound will delete the passed file. Like with mIsASound, it does not verify that the passed file is an legitimate sound file and will delete any file.

Possible errors are:

Error Number			Meaning
	0				No Error
	-4				Sound is busy (being played or recorded)
	-35			Bad file name
	-36			I/O error
	-37			Bad file name
	-43			File not found
	-44			Disk is write-protected
	-45			File is locked
	-46			Volume is locked
	-47			File is busy
	-120			Invalid directory or bad pathname

Sample scripts:

-- Given the name of a sound (e.g. “Boom”), this will delete
-- the file
on DeleteSound localName
	global gSoundObj

	gSoundObj(mDeleteSound, the pathname & localName )
end DeleteSound 

-- Deletes a specific sound
on DeleteMySound
	global gSoundObj

	gSoundObj(mDeleteSound, “HD:Sounds:Nails on Chalkboard” )
end DeleteMySound

Note: If a -43 error is returned with this function while using the Windows XObject, it indicates a general file error.

mSetStartTime

Returns: An error number, zero if none
Parameters:
<start point> An integer describing the start time of a sound, in milliseconds which must be zero or greater.

mSetStartTime should be used along with mSetEndTime to specify a segment of a sound file to be played. By default, the entire sound file will be played. Currently, the Sound XObject doesn’t provide the ability to get the length of a sound file.

Possible errors are:

Error Number			Meaning
	0				No Error
	-1				Bad parameter 
	-4				Sound is busy (being played or recorded)

Sample scripts:

-- This will set the start time of a sound in seconds
on SetStart theSeconds
	global gSoundObj

	-- Convert from seconds to milliseconds
	set milliseconds = theSeconds * 1000

	gSoundObj(mSetStartTime, milliseconds)
end SetStart	

mSetEndTime

Returns: An error number, zero if none
Parameters:
<start point> An integer describing the end time of a sound, in milliseconds which must be zero or greater.

mSetEndTime should be used along with mSetStartTime to specify a segment of a sound file to be played. By default, the entire sound file will be played. Currently, the Sound XObject doesn’t provide the ability to get the length of a sound file.

Note: If the start time is greater than the end time when mPlay is called, the entire sound file will be played.

Possible errors are:

Error Number			Meaning
	0				No Error
	-1				Bad parameter 
	-4				Sound is busy (being played or recorded)

Sample scripts:

-- This will set the end time of a sound in seconds
on SetEnd theSeconds
	global gSoundObj

	-- Convert from seconds to milliseconds
	set milliseconds = theSeconds * 1000

	gSoundObj(mSetEndTime, milliseconds)
end SetEnd

mClearStartEnd

Returns: nothing
Parameters: none

mClearStartEnd will clear any start and end points set my mSetStartTime and mSetEndTime so that the entire sound file will be played.

Note: Though this method may be called at any time, it will not affect a sound that is currently being played, just the sounds that are triggered with mPlay subsequently.

Sample scripts:

-- A very easy script
on ClearStartEnd
	global gSoundObj

	if(objectP) gSoundObj then gSoundObj(mClearStartEnd)

end ClearStartEnd

mSetSampleRate

Returns: 
Parameters:
<integer equivalent> An integer describing the sample rate to use. Please refer to Table 2 to see which values correspond to each sampling rate.

mSetSampleRate will set the sampling rate of the sound. The default sampling rate will be set to the default rate of the sound input driver which is usually 22 kHz or 22.050 kHz (for the Macintosh) and 11.025 kHZ (for Windows, at least with my sound card)

Note: The sample rate cannot be changed while a sound is being recorded or while a recording is paused. If you do so, you will get -4 error, indicating that the sound is busy.

Likely errors are:

Error Number			Meaning
	0				No Error
	-1				Bad parameter
	-2				Sound input driver not open
	-4				Sound is busy
	-225			Sample rate not supported

Example scripts:

-- This handler will set the sampling rate to the highest possible
-- for the current input device
on SetBestSampling
	global gSoundObj

	if objectP(gSoundObj) then

		-- A value of 6 indicates the best sampling rate possible
		set err = gSoundObj(mSetSamplingRate, 6)
	end if

end SetBestSampling

-- This handler will try to set the sampling rate to 44kHz and if
-- not available will set to 22kHz.
on Set44Sampling
	global gSoundObj

	if objectP(gSoundObj) then

		-- A value of 5 indicates 44kHz sampling
		set err = gSoundObj(mSetSamplingRate, 5)

		-- If 44kHz isn’t supported, try to go to 22.050 kHz
		if err = -225 then set err = gSoundObj(mSetSamplingRate, 4)

		-- If 22.050 kHz, set to 22kHz (sound drivers may vary)
		if err = -225 then set err = gSoundObj(mSetSamplingRate, 3)

		-- If this doesn’t work, we’re going to have a very low
		-- sound quality
		if err = -225 then
			set err = gSoundObj(mSetSamplingRate,6)
			alert “Your recordings will not sound so good.”
		end if
	end if

end Set44Sampling

mSetSampleDepth

Returns: an error number, zero if no error occurred
Parameters:
<sample depth> An integer describing the depth (e.g. 8-bit or 16-bit) of the sound. Pass zero if you want the depth set to the highest possible.

mSetSampleDepth will set the sampling size of the sound. The default sampling size will be the default for the sound input driver.

Note: The sample depth cannot be changed while a sound is being recorded or while a recording is paused. If you do so, you will get -4 error, indicating that the sound is busy.

Likely errors are:

Error Number			Meaning
	0				No Error
	-1				Bad parameter
	-2				Sound input driver not open
	-4				Sound is busy
	-226			Sample depth not supported

Example scripts:

-- This handler will set the sampling depth to the highest possible
-- for the current input device
on SetBestDepth
	global gSoundObj

	if objectP(gSoundObj) then

		-- A value of 0 indicates the best sampling depth possible
		set err = gSoundObj(mSetSamplingDepth, 0)
	end if

end SetBestDepth

-- This handler will try to set the sampling depth to 16-bit
-- If not available, it will set it to 8-bit
on Set16bitRecording
	global gSoundObj

	if objectP(gSoundObj) then

		set err = gSoundObj(mSetSamplingRate, 16)

		-- 16-bit sound isn’t available, support 8-bit instead
		if err = -225 then
			set err = gSoundObj(mSetSamplingRate, 8)
			alert “This microphone doesn’t support 16-bit sound. ¬
8-bit sound will be recorded instead”
		end if
	end if
end Set16bitRecording

mSetCompression

Returns: an error number, zero if no error occurred
Parameters:

<new compression value> This is an integer representing the type of compression you want to use. See table 3 for the compression types.

mSetCompression tries to use MACE compression for sound files which is not supported for WAVE files. Calling this has no effect under Windows.

mSetCompression will direct the Sound XObject to compress any recorded sound. Currently, the compression types that are supported are MACE 3:1, MACE 6:1, IMA 4:1and µLaw (2:1) compression may be supported in future versions of the Sound XObject when it is built into Apple’s Sound Manager. Whether or not compression is available depends completely on the sound input driver and compression support often varies with different sample rate and sample depth settings.

Note: IMA and µLaw are very new compression types and most machines will not support recording directly of these types. However, this should be available with future Macintosh models and in either case, the Sound XObject can play either type.

Another note: The compression rate cannot be changed while a sound is being recorded or while a recording is paused. If you do so, you will get -4 error, indicating that the sound is busy.

Likely errors are:

Error Number			Meaning
	0				No Error
	-1				Bad parameter
	-2				Sound input driver not open
	-4				Sound is busy
	-223			This compression rate is not supported

Sample scripts:

-- Attempts to set compression to MACE 3:1
on SetIntermediateCompression
	global gSoundObj

	if objectP(gSoundObj) then
		-- A value of 3 indicates MACE 3:1 compression
		set err = gSoundObj(mSetCompression, 3)
	end if
end SetIntermediateCompression

mGetInputLevel

Returns: A value between 0-255 indicating the input level (0 is none, 255 is the maximum). If this number is negative, an error occurred
Parameters: None

mGetInputLevel can be called anytime (on the Macintosh side), as long as the sound input driver has been opened successfully. If a microphone is not plugged in, it will return a zero or very low value.

An important note for Windows: Due some limitations of Window’s MCI protocol, mGetInput can only return a value when a sound has been opened with mSetSoundFile and it is not recording, played or paused. I’m not happy with this either. Also, since many of the Windows error numbers are positive numbers, this will return a value of -1 if a Windows error occurred. If you get a -1 return value, you should check the last error number with mGetError.

Another Windows note: Internally, the Windows MCI engine returns a sample level between 0 and 128. To ensure cross-platform compatibility, this number is doubled (and if the sample level was 128, it is set to 255). Consequently, you will not get odd-numbered sample values for Windows.

Error numbers that you may see are:

Error Number			Meaning
	-1				An error occurred (Windows). Check the last error with mGetError.
	-2				Sound input driver not open
	-4				Sound is busy playing, recording or paused (Windows only)
	-8				MCI device is not open. A sound file must be specified with mSetSoundFile 					beforehand
	-221			Error querying the sound input device

Sample scripts:

-- Returns the current input level, zero if an error occurred
on GetInputLevel
	global gSoundObj, gErrNum

	set level = gSoundObj(mGetInputLevel)

	-- if the level is -1, get the error number.
	if level < 0 then
		set gErrNum = gSoundObj(mGetError)
		set level = 0
	end if

	return level
end GetInputLevel

mFreeRecordingTime

Returns: The free recording time on the drive where the current sound file resides, in milliseconds
Parameters: None

mFreeRecordingTime will let you know how much recording space you have available given the current sample rate, sample depth and compression settings for a file that has been prepared for recording with mSetSoundFile.

If a negative number is returned, an error occurred.

Error numbers that you may encounter are:

Error Number			Meaning
	-2				Sound input driver not open
	-3				No sound specified (see mSetSoundFile)
	-7				Too much hard drive space
	-221			Error querying the sound input device

If you get a -7 error, this means that the hard drive to which you are recording has over 2 gigabytes of space on it (Macintosh only).

Note for Windows: mFreeRecordingTime is not supported under Windows and will always return a value of zero.

Sample scripts:

-- Returns the amount of recording time, in seconds
on GetFreeTime
	global gSoundObj
	
	set result = gSoundObj(mFreeRecordingTime)
	if result < 0 then set freeSeconds = 0
	else set freeSeconds = result/1000

	return freeSeconds
end GetFreeTime

Advanced Tips & Techniques

I encourage you to take a look at the Lingo scripts in the sample movie that I have included. It does get confusing in certain places such as in Director’s idle handler.

If the XObject does not get instantiated for some reason, the error code and an error message will be passed back in two global variables as strings. The global variable, gXObjErrStr, contains a string describing an error message and the global variable, gXObjErrNum, holds a string of the error number (a string of “0” indicates no error occurred). You will not need to use the global variables except in dire circumstances.

When instantiating the XObject, you have the option to pass a buffer size for the playback of sounds. The larger the size, the less impact playing the sound should have on the disk. This may be especially useful for playing sounds off of a CD where playback from disk often results in stuttering sounds. The tradeoff of increasing the size of the buffer is that the RAM used will not be released from memory until the instance of the XObject is released using mDispose. Also, make sure that if you do increase the buffer size that pass in a value which is a multiple of 4.

Compatibility issues, known bugs and other oddities

Software is never perfect and neither is the Sound XObject. I do not guarantee the XObject work on every Macintosh and sound card around and it may not work on future models. If you do have a compatibility problem or find a bug in the Sound XObject, please let me know. Below is a list of known problems:

Macintosh:
(1) On 68K AV Macs (i.e. the Quadra 840AV and the Quadra 660AV),  recording 8-bit, 22kHz will result in a scratchy sound that is not pleasant to the ears when using the Sound Manager 3.0 and earlier. To avoid this problem, make sure these users are running version 3.1 of the Sound Manager or later.

(2) When running a compiled projector on the 660AV and 840AV with system software before system 7.5, the XObject may not be instantiated correctly when running the Sound Manager 3.0 and earlier.

(3) In general, systems running the 2.0 Sound Manager will be slower.

(4) The Sound XObject is unable to record sound at an 11kHz sample rate when using the MacRecorder.

Windows:
(1) Sometimes the Windows operating system will intervene and pose a standard dialog such as a dialog box stating that drive B cannot be read from.

(2) The Windows Sound XObject will not be able to get level readings when in a repeat loop if the exitLock has been set to true by Lingo.

Enjoy!

Sound XObject, copyright (c) 1994, 1995 by Red Eye Software
Written by Scott Kildall

@∫Pf=|˝Ê`RD`ˇ 
n˝Êg˝"Jn˝Êf<.˝Í`˝?*≤?*∞?*Æ?*¨?.˝Ú/?.˝ËHnˇ˙/N∫È2
@OÔf¸‰
jÙ≤l*z`0*≤H¿ÂàAÍﬁ–à0E∂P˙